﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestAssignIndexedDenseSymmetricMatrix.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.Tests.DenseSymmetricMatrixTest
{
    #region Usings

    using System;
    using System.Globalization;

    using ExulLibrary.Exceptions;

    using NUnit.Framework;

    #endregion

    /// <summary>
    ///     Test suite for
    ///     <see cref="DenseSymmetricMatrixExtensions.Assign{T}(DenseSymmetricMatrix{T},int[],int[],DenseSymmetricMatrix{T})"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.Sequential.DenseSymmetricMatrixExtensions")]
    public sealed class TestAssignIndexedDenseSymmetricMatrix
    {
        /// <summary>
        ///     Tests the method when indexes of target elements are non-negative and less than
        ///     size of dimensions of target matrix.
        /// </summary>
        [Test]
        public void WhenTargetIndexesAreValid()
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);

            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);

            var targetRowsIndexes = new[] { 0, 2 };
            var targetColumnsIndexes = new[] { 0, 1 };
            var expectedResult = new double[]
                                 {
                                     1,
                                     20, 30,
                                     2, 3, 60
                                 };

            // Act
            target.Assign(targetRowsIndexes, targetColumnsIndexes, source);

            // Assert
            Assert.That(target.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when targetRowsIndexes parameter is empty collection.
        /// </summary>
        [Test]
        public void WhenTargetRowsIndexesCollectionIsEmpty()
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);

            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);

            var targetRowsIndexes = new int[0];
            var targetColumnsIndexes = new[] { 0, 1 };
            var expectedResult = new double[]
                                 {
                                     10,
                                     20, 30,
                                     40, 50, 60
                                 };

            // Act
            target.Assign(targetRowsIndexes, targetColumnsIndexes, source);

            // Assert
            Assert.That(target.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when targetColumnsIndexes parameter is empty collection.
        /// </summary>
        [Test]
        public void WhenTargetColumnsIndexesCollectionIsEmpty()
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);

            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);

            var targetRowsIndexes = new[] { 0, 2 };
            var targetColumnsIndexes = new int[0];
            var expectedResult = new double[]
                                 {
                                     10,
                                     20, 30,
                                     40, 50, 60
                                 };

            // Act
            target.Assign(targetRowsIndexes, targetColumnsIndexes, source);

            // Assert
            Assert.That(target.Values, Is.EquivalentTo(expectedResult));
        }

#if SAFE

        /// <summary>
        ///     Tests the method when target parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenTargetIsNull()
        {
            // Arrange
            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);
            var targetRowsIndexes = new[] { 0, 2 };
            var targetColumnsIndexes = new[] { 0, 1 };

            // Act and Assert
            Assert.That(
                () => DenseSymmetricMatrixExtensions.Assign(null, targetRowsIndexes, targetColumnsIndexes, source),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("target"));
        }

        /// <summary>
        ///     Tests the method when targetRowsIndexes parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenTargetRowsIndexesIsNull()
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);
            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);
            var targetColumnsIndexes = new[] { 0, 1 };

            // Act and Assert
            Assert.That(
                () => target.Assign(null, targetColumnsIndexes, source),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("targetRowsIndexes"));
        }

        /// <summary>
        ///     Tests the method when targetColumnsIndexes parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenTargetColumnsIndexesIsNull()
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);

            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);
            var targetRowsIndexes = new[] { 0, 2 };

            // Act and Assert
            Assert.That(
                () => target.Assign(targetRowsIndexes, null, source),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("targetColumnsIndexes"));
        }

        /// <summary>
        ///     Tests the method when source parameter is <see langword="null"/>.
        /// </summary>
        [Test]
        public void WhenSourceIsNull()
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);
            var targetRowsIndexes = new[] { 0, 2 };
            var targetColumnsIndexes = new[] { 0, 1 };

            // Act and Assert
            Assert.That(
                () => target.Assign(targetRowsIndexes, targetColumnsIndexes, null),
                Throws.TypeOf<ArgumentNullException>().With.Property("ParamName").EqualTo("source"));
        }

        /// <summary>
        ///     Tests the method when an index of row of target element is negative or greater than or equal to
        ///     the size of the target matrix.
        /// </summary>
        /// <param name="position">
        ///     The index of the element in the storage.
        /// </param>
        /// <param name="targetRowIndex">
        ///     The row index of the element.
        /// </param>
        [Test]
        public void WhenATargetRowIndexIsOutOfRange([Values(0, 1)] int position, [Values(-1, 3)] int targetRowIndex)
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);

            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);
            var targetRowsIndexes = new int[2];
            targetRowsIndexes[position] = targetRowIndex;

            var targetColumnsIndexes = new[] { 0, 1 };

            // Act and Assert
            var parameterName = string.Format(CultureInfo.InvariantCulture, "targetRowsIndexes[{0}]", position);
            Assert.That(
                () => target.Assign(targetRowsIndexes, targetColumnsIndexes, source),
                Throws.TypeOf<ElementIndexIsOutOfRangeException>().With.Property("ParamName").EqualTo(parameterName));
        }

        /// <summary>
        ///     Tests the method when a column index of target element is negative or greater than or equal to the size
        ///     of the target matrix.
        /// </summary>
        /// <param name="position">
        ///     The index of the element in the storage.
        /// </param>
        /// <param name="targetColumnIndex">
        ///     The column index of the element.
        /// </param>
        [Test]
        public void WhenATargetColumnIndexIsOutOfRange([Values(0, 1)] int position, [Values(-1, 3)] int targetColumnIndex)
        {
            // Arrange
            var targetData = new double[]
                             {
                                 10,
                                 20, 30,
                                 40, 50, 60
                             };
            var target = new DenseSymmetricMatrix<double>(targetData);

            var sourceData = new double[]
                             {
                                 1,
                                 2, 3
                             };
            var source = new DenseSymmetricMatrix<double>(sourceData);
            var targetRowsIndexes = new[] { 0, 2 };
            var targetColumnsIndexes = new int[2];
            targetColumnsIndexes[position] = targetColumnIndex;

            // Act and Assert
            var parameterName = string.Format(CultureInfo.InvariantCulture, "targetColumnsIndexes[{0}]", position);
            Assert.That(
                () => target.Assign(targetRowsIndexes, targetColumnsIndexes, source),
                Throws.TypeOf<ElementIndexIsOutOfRangeException>().With.Property("ParamName").EqualTo(parameterName));
        }

#endif
    }
}